import { reactive } from "vue";

function useBaiduMap() {
    // 定义相关地图变量
    let BMap: any,
        map: any;

    // 存放异步添加控件函数
    const controlStack: Array<Function> = [];

    // 存放地图对应事件栈
    const eventStack: Array<Function> = [];

    // 初始化百度地图标签
    function initMap(classId: string) {
        createMap(classId);
    }

    // 创建地图逻辑
    function createMap(classId: string): void {
        const script: HTMLScriptElement = document.createElement('script');
        script.type = 'text/javascript';
        script.className = '_initMap';
        script.src = 'https://api.map.baidu.com/getscript?v=3.0&ak=BwGFZoXtrM4pMcQosUwRYcNYzOCTW9lX';
        script.onload = () => {
            // 保存BMap对象
            BMap = reactive(window.BMap);
            // 保存map对象
            map = reactive(new BMap.Map(classId));
            // 设置地图初始中心位置和缩放
            map.centerAndZoom(
                new BMap.Point(119.30347, 26.080429), // 经纬度
                11 // 缩放
            );
            map.setCurrentCity('福州市');
            map.enableScrollWheelZoom(true);
            /*
            * 若控制器栈中有对象存在，
            * 则将控制器添加至地图中
            * */
            controlStack.length > 0
            &&
            controlStack.forEach(item => {
                item(window);
            });
            /*
            * 与控制器栈道理类似
            * */
            eventStack.length > 0
            &&
            eventStack.map(item => item());
        };
        const _initMap: HTMLCollectionOf<Element> = document.getElementsByClassName('_initMap');
        /* _initMap 为元素集合, 是一个伪数组
           想要使用Array.map()方法可以使用call
           可以使用[].map.call()
           或者是 Array.prototype.map.call()
        */

        [].map.call(_initMap, (map) => {
            /* _initMap不为空，说明页面上已经存在了地图script标签
               这里我选择全部删除后再重新插入
            */
            if (document.body.contains(map)) {
                /*
                * 修复移除bug
                * */
                document.body.removeChild(map);
            }

        });

        // 将script标签插入到body中
        document.body.appendChild(script);
    }

    // 添加控件方法
    function addController(controlName: string, props: any): any {
        /*
            添加控件之前需要判断地图是否加载完成,
            大部分情况下调用initMap之后使用hooks提供的添加控件方法
            都会出现map undefined的情况，因此在这里使用异步栈完成
            将对应方法添加到控件栈中，待 onload 执行到异步栈任务时触发
         */

        // 因为地图异步加载的原因，如果直接传参window.BMAP.*
        // 时, script标签未加载，window对象中不含BMAP属性
        // 使用正则匹配需要使用到window对象
        for (const key in props) {
            if (props.hasOwnProperty(key)) {
                /^BMAP/.test(props[key]) && (props[key] = window[props[key]]);
            }
        }
        if (map) {
            map.addControl(new BMap[controlName](props));
        } else {
            controlStack.push((window: any) => {
                map.addControl(new BMap[controlName](props))
            });
        }
    }

    // 添加地图事件方法
    function addEventControl(event: string, callback: Function) {
        if (map) {
            map.addEventListener(event, (e: Event) => {
                callback(e, map)
            }, false);
        } else {
            eventStack.push(() => {
                map.addEventListener(event, (e: Event) => {
                    callback(e, map)
                }, false);
            })
        }
    }

    return {
        initMap,
        addController,
        addEventControl
    }
}

export default useBaiduMap;
